#ifndef XGE_XTHREADMANAGER_H_
#define XGE_XTHREADMANAGER_H_
#include "xge_common_config.h"
#include "xstring.h"
#include "xsync.h"
#include "xdata_structure.h"
#include "xthread.h"
#include "xthread_delegate.h"
#include <Windows.h>

namespace xge{
namespace xge_internal{
  // This class is the helper class for ThreadManager
  // not using it directly .
  // It provide thread-safe wrapper for the Map operation
  // Map has a very important feature which is the existed iterator won't
  // crash or changed even if the map itself changed
  // Which means , in one thread , we can do the operation of map , in another thread
  // the existed iterator is also working well.
  // In fact , this class can lay inside of ThreadManager , however , it looks ugly when
  // I do this , so I place it outside .
  class ThreadManager;
  template < typename T > class ThreadManagerContext {
  private:
    friend class ThreadManager;
    // the ThreadHandlerPtr map
    // the ThreadManager will store the running thread handler in this map
    // and it will make sure that the thread can have safe memory to use typedef 
    typedef typename xge::map< xge::String , T* >::Map RunningThreadHandlerMap;
    typedef typename RunningThreadHandlerMap::iterator Iterator;
    typedef typename RunningThreadHandlerMap::value_type ValueType;
    typedef std::pair< Iterator , bool > InsertRet;

    // Insert a key associated with value into the map
    // this Insert is thread_safe
    InsertRet Insert( const String& key , T* val ) {
      AutoLock<FastLock> l(lock_);
      return thread_handler_map_.insert( ValueType(key,val) );
    }
    // Erase a specific iterator
    void Erase( Iterator it ) {
      AutoLock<FastLock> l(lock_);
      thread_handler_map_.erase(it);
    }
    // Test if the iterator is end
    bool End( Iterator it ) const {
      return thread_handler_map_.end() == it;
    }
    // Find a target by key(name)
    Iterator Find( const String& name ) {
      AutoLock<FastLock> l(lock_);
      return thread_handler_map_.find(name);
    }
    // Size of the map
    size_t size() const {
      return thread_handler_map_.size();
    }
    // Get the map itself
    RunningThreadHandlerMap& GetMap() {
      return thread_handler_map_;
    }
    // Clear the map 
    // Just clear , this will ruin the existed iterator
    // because all the nodes do not exist after calling this
    void Destroy() {
      AutoLock<FastLock> l(lock_);
      thread_handler_map_.clear();
    }

  private:
    // Some debug information helper routine
    bool IsBackThread( const String& thread_name ){
      return !End(Find(thread_name));
    }
    bool IsBackThread( const size_t thread_id ) {
      AutoLock<FastLock> l(lock_);
      for( Iterator ib = thread_handler_map_.begin() , ie = thread_handler_map_.end() ; ib != ie ; ++ib ) {
        T* t = (*ib).second;
        if( (t->thread_handler)->GetUniqueThreadID() == thread_id ) {
          return true;
        }
      }
      return false;
    }
    const ThreadHandlerPtr& GetWeakXThreadHandlerByName( const String& thread_name );
  private:
    // thread handler map
    // it stores the running thread handler with its delegate
    RunningThreadHandlerMap thread_handler_map_;
    // a lock (XFastLock is implemented as Critical Section)
    FastLock lock_;
  };


    // Coding thread class always seems to be very subtle , for c++ do not support concurrent memory model
    // we will never be aware of when we will use the memory , when is proper to delete the thread .
    // We change the original model of coding thread
    // We separate thread as below .
    // 1. ThreadDelegate 
    //    This is a virtual class , which you only need to rewrite the specific function , wherein is the code
    //    the thread will execute ! But this will be shared with different thread ?
    // 2. ThreadHandler
    //    This is a specific class , which you will never be able to new and delete , you will only get the 
    //    smart_ptr of this class .
    // 3. ThreadManager
    //    A class provide function to deal with the thread spawn and reactive .
    //    The thread manager will ONLY receive the smart_ptr version of ThreadDelegate in order to deal with the memory
    //    sharing stuff .

  class ThreadManager : public AllStatic {
    // Using an ugly macro to enable inline and
    // some other stuff
#ifdef _DEBUG
  private:
    static FORCEINLINE bool IsInitializedBefore() {
      return kContext != NULL ;
    }
#define CHECK_INITIALIZE XASSERT(IsInitializedBefore())
#else
#define CHECK_INITIALIZE 
#endif

  public:

    // status code
    enum {
      EC_OK = 0, // success
      EC_CREATE_ERROR = 1, // create thread encounter error ,see detail in log file
      EC_NAME_COLLISION=2, // name collision for the thread name
      EC_OTHER_ERROR = 3   // other error
    };

    // Sleep the current callee thread at most ms 'ms'
    static void SleepCurrentThread(
      size_t ms
      );

    // Switch to another thread , so this thread will give
    // up all its time slice

    static void SwithToAnotherThread();

    // Create a thread to run 
    // This function will create a internal xthread and run as right_away indicate
    // if it succeed :
    // the function  returns a not NULL XThreadHandlePtr which is a shared_ptr
    // you can check the shared_ptr.Null() function to testify if it is ok 
    // and you can use this ThreadHandler to control the thread as you wish
    // and it will internally hold the thread_delegate_shared_ptr in order to
    // ensure the memory is in the right track 
    // and what is more , it will also have another ThreadHandlerPtr as well
    // You may use the function like this:
    // class MyThreadMain: public XThreadDelegate {};
    // ThreadDelegatePtr myDelegate( new MyThreadMain() );
    // ThreadHandlerPtr handler = CreateXThread( myDelegate );
    // if you do not want to have the handler now 
    // you just code: handler.Reset();
    // now the handler has been set to NULL 
    // you have no control to use this 
    // if you want to destroy the handler
    // code:
    // myDelegate.Reset();
    // when the thread run over all the memory will be deleted automatically now.
    static ThreadHandlerPtr CreateXThread( 
      int* error_code ,
      const ThreadDelegatePtr& thread_delegate , // the delegate smart ptr
      const String& thread_name ,
      const char* debug_name = NULL ,
      bool right_away = true );

    static size_t GetAllocatedThreadSize() {
      CHECK_INITIALIZE;
      return kContext->size();
    }
    // Get the current calling thread id
    static size_t GetCurrentThreadUniqueID();
  public:
    // This function MUST be called before any function calling from this class
    // It is the basically initialize function , and It Bind The calling thread 
    // as the Main Thread . 
    static bool Initialize();

    static FORCEINLINE bool IsInBackThread( const String& thread_name ) {
      CHECK_INITIALIZE;
      return kContext->IsBackThread(thread_name);
    }
    static FORCEINLINE bool IsInBackThread( size_t thread_id ) {
      CHECK_INITIALIZE;
      return kContext->IsBackThread(thread_id);
    }
    static FORCEINLINE bool IsInMainThread() {
      CHECK_INITIALIZE;
      return kMainThreadID == GetCurrentThreadUniqueID();
    }
      
  private:
    // Notify the termination of a certain thread
    // This function is always called after the ThreadHandler::Kill
    // the kill will terminate the thread right away
    // and than call this function to drop the shared_ptr of every
    // thread 
    static bool NotifyThreadTermination( const String& thread_name );
    // friend class is XThread
    // since XThread will using some internal thread function here
    friend class ThreadHandler;
    // The real thread main entry function
    static unsigned int __stdcall ThreadMainFunc(
      void* argument  
      ); 

    // Exit code of a general Win32 thread
    enum {
      XTHREAD_GENERAL_EXIT_CODE = NORMAL_EXIT_CODE
    };
    // Manage data 
    struct XThreadManageData : public Allocator{
      ThreadHandlerPtr thread_handler;
      ThreadDelegatePtr thread_delegate;
      XThreadManageData( ThreadHandler* handler_ptr , const ThreadDelegatePtr delegate_ptr ) :
      thread_handler(handler_ptr) , thread_delegate(delegate_ptr) {}

    };
    // XThread Manager Helper Context 
    typedef ThreadManagerContext<XThreadManageData> XContext;
    // destroy the thread manager itself
    static bool DestroyXThreadManager( void* argument );
    // We simply use a pointer to do this
    // instead of using Fancy XLazyInstance , since we will
    // call Initialize explicitly , so we do not need using
    // XLazyInstance class .
    static XContext* kContext;
    // simply use a id to indicate the current thread
    // since it is easy and safe to do this 
    static size_t kMainThreadID;
    // The max unfinished thread join time ( micro-second )
    static const size_t kAtExitMaxJoinTime = 200;

  };

#undef CHECK_INITIALIZE


} // namespace xge_internal
}// namespace xge


#endif// 